#!/usr/bin/env python
#
#       This is a program for all ADC Module. It 
#   convert analog singnal to digital signal.
#
#       This program is most analog signal modules' 
#   dependency. Use it like this:
#       `import ADC0832`
#       `sig = ADC0832.getResult(chn)`
#
#   *'chn' should be 0 or 1 represent for ch0 or ch1
#   on ADC0832
#       
#         ACD1302                 Pi
#           CS ---------------- Pin 11
#           CLK --------------- Pin 12
#           DI ---------------- Pin 13

#           VCC ----------------- 3.3V
#           GND ------------------ GND
#

import RPi.GPIO as GPIO     # 导入GPIO库
import wiringpi             # 使用wiringpi库控制ADC0832
import time                 # 时间模块用于时间测量

# 定义ADC0832模块的引脚
ADC_CS  = 17 #11  # 片选引脚（Chip Select），默认为GPIO17（物理引脚11）
ADC_CLK = 18 #12  # 时钟引脚（Clock），默认为GPIO18（物理引脚12）
ADC_DIO = 27 #13  # 数据输入输出引脚（Data I/O），默认为GPIO27（物理引脚13）

# 初始化ADC0832模块
# using default pins for backwards compatibility
def setup(cs=17,clk=18,dio=27): #11,12,13
    """初始化ADC0832模块的GPIO引脚配置
    参数:
        cs (int):  片选引脚BCM编号，默认17
        clk (int): 时钟引脚BCM编号，默认18
        dio (int): 数据引脚BCM编号，默认27
    """
    global ADC_CS, ADC_CLK, ADC_DIO
    ADC_CS=cs
    ADC_CLK=clk
    ADC_DIO=dio
    GPIO.setwarnings(False)  # 禁用GPIO警告
    GPIO.setmode(GPIO.BCM)   # 使用BCM引脚编号模式
    GPIO.setup(ADC_CS, GPIO.OUT)   # 配置CS引脚为输出模式
    GPIO.setup(ADC_CLK, GPIO.OUT)  # 配置CLK引脚为输出模式

def destroy():
    """清理GPIO资源，程序退出时调用"""
    GPIO.cleanup()

# using channel = 0 as default for backwards compatibility
def getResult(channel=0):                   # Get ADC result, input channal
    """从指定通道读取ADC转换结果（8位分辨率）
    参数:
        channel (int): 输入通道0或1
    返回:
        int: 0-255范围的数字量，若数据校验失败返回0
    """
    # 初始化通信时序
    GPIO.setup(ADC_DIO, GPIO.OUT)
    GPIO.output(ADC_CS, 0)          # 使能ADC（CS低电平有效）
    
    # 发送起始位（Start Bit）
    GPIO.output(ADC_CLK, 0)
    GPIO.output(ADC_DIO, 1); wiringpi.delayMicroseconds(2)  # 起始位第一位高电平
    GPIO.output(ADC_CLK, 1);  wiringpi.delayMicroseconds(2) # 时钟上升沿
    GPIO.output(ADC_CLK, 0)          # 时钟下降沿完成起始位第一部分

    GPIO.output(ADC_DIO, 1);  wiringpi.delayMicroseconds(2) # 起始位第二位高电平
    GPIO.output(ADC_CLK, 1);  wiringpi.delayMicroseconds(2)
    GPIO.output(ADC_CLK, 0)          # 完成起始位第二部分

    # 发送通道选择位（单端模式）
    GPIO.output(ADC_DIO, channel);  wiringpi.delayMicroseconds(2)  # 0=通道0，1=通道1
    GPIO.output(ADC_CLK, 1)          # 时钟上升沿锁存通道选择
    GPIO.output(ADC_DIO, 1);  wiringpi.delayMicroseconds(2)  # 结束通道选择
    GPIO.output(ADC_CLK, 0)
    GPIO.output(ADC_DIO, 1);  wiringpi.delayMicroseconds(2)

    # 读取第一个8位数据（MSB first）
    dat1 = 0
    for i in range(0, 8):
        GPIO.output(ADC_CLK, 1);  wiringpi.delayMicroseconds(2)  # 上升沿产生
        GPIO.output(ADC_CLK, 0);  wiringpi.delayMicroseconds(2)  # 下降沿读取数据
        GPIO.setup(ADC_DIO, GPIO.IN)  # 切换DIO为输入模式
        dat1 = dat1 << 1 | GPIO.input(ADC_DIO)  # 左移并拼接数据位
    
    # 读取第二个8位数据（LSB first）用于校验
    dat2 = 0
    for i in range(0, 8):
        dat2 = dat2 | GPIO.input(ADC_DIO) << i  # 直接按位拼接
        GPIO.output(ADC_CLK, 1);  wiringpi.delayMicroseconds(2)
        GPIO.output(ADC_CLK, 0);  wiringpi.delayMicroseconds(2)
    
    # 结束通信
    GPIO.output(ADC_CS, 1)           # 禁用ADC（CS高电平）
    GPIO.setup(ADC_DIO, GPIO.OUT)    # 重置DIO为输出模式

    # 校验两个数据包，相同则返回，否则返回0
    if dat1 == dat2:
        return dat1
    else:
        return 0

def getResult1():
    """专用函数直接读取通道1的ADC值"""
    return getResult(1)

def loop():
    """持续循环读取并打印两个通道的ADC值"""
    while True:
        res0 = getResult(0)
        res1 = getResult(1)
        print ('res0 = %d, res1 = %d' % (res0,res1))
        time.sleep(0.4)  # 400ms间隔读取

if __name__ == '__main__':      # Program start from here
    setup()
    try:
        loop()
    except KeyboardInterrupt:   # When 'Ctrl+C' is pressed, the child program destroy() will be  executed.
        destroy()